using System;
using System.Collections.Generic;

namespace Windy.Transformations
{
    public abstract class CachedTransformSinkBase<TInput, TOutput, TClass> : TransformSinkBase<TInput, TOutput, TClass>
        where TClass : CachedTransformSinkBase<TInput, TOutput, TClass>
    {
        #region Initializers

        #region Constructors

        protected CachedTransformSinkBase()
        { }

        #endregion

        protected virtual void Initialize(
            Action<int, TInput> voidTransformSink,
            Action<int, TInput, TOutput> monoTransformSink,
            Action<int, TInput, IEnumerable<TOutput>, Action<Action>> varyTransformSink,
            Action transformBeginHandler,
            Action transformCompleteHandler,
            Action transformAbortHandler)
        {
            VoidTransformSink = voidTransformSink;
            MonoTransformSink = monoTransformSink;
            VaryTransformSink = varyTransformSink;

            base.Initialize(
                transformBeginHandler,
                transformCompleteHandler,
                transformCompleteHandler);
        }

        #endregion

        #region Contract Stubs

        protected abstract void RecordAction(Action action);
        protected abstract void BeginRecordActions();
        protected abstract void AbandonActions();
        protected abstract void ApplyActions();

        #endregion

        #region Overides

        #region Transform Data Sinks

        protected Action<int, TInput> VoidTransformSink;
        public override void OnVoidTransform(int index, TInput inputItem)
        {
            if (VoidTransformSink != null)
            {
                RecordAction(() => VoidTransformSink(index, inputItem));
            }
        }
        public TClass SetupVoidTransformSink(Action<int, TInput> sink)
        {
            VoidTransformSink = sink;
            return this as TClass;
        }

        protected Action<int, TInput, TOutput> MonoTransformSink;
        public override void OnMonoTransform(int index, TInput inputItem, TOutput outputItem)
        {
            if (MonoTransformSink != null)
            {
                RecordAction(() => MonoTransformSink(index, inputItem, outputItem));
            }
        }
        public TClass SetupMonoTransformSink(Action<int, TInput, TOutput> sink)
        {
            MonoTransformSink = sink;
            return this as TClass;
        }

        protected Action<int, TInput, IEnumerable<TOutput>, Action<Action>> VaryTransformSink;
        public override void OnVaryTransform(int index, TInput inputItem, IEnumerable<TOutput> outputItems)
        {
            if (VaryTransformSink != null)
            {
                VaryTransformSink(index, inputItem, outputItems, RecordAction);
            }
        }
        public TClass SetupVaryTransformSink(Action<int, TInput, IEnumerable<TOutput>, Action<Action>> sink)
        {
            VaryTransformSink = sink;
            return this as TClass;
        }

        #endregion

        #region Transform Workflow Handlers

        public override void OnTransformBegun()
        {
            base.OnTransformBegun();
            BeginRecordActions();
        }
        public override void OnTransformAborted()
        {
            AbandonActions();
            base.OnTransformAborted();
        }
        public override void OnTransformCompleted()
        {
            ApplyActions();
            base.OnTransformCompleted();
        }

        #endregion

        #endregion
    }
}
